Перейти к основному содержимому

6.11. Shared Nothing Architecture

Разработчику Архитектору Аналитику

Shared Nothing Architecture

Суть архитектуры

Shared Nothing Architecture — это подход к построению распределённых вычислительных систем, в котором каждый узел функционирует полностью автономно. Узел обладает собственным процессором, оперативной памятью и локальным дисковым хранилищем. Никакие ресурсы между узлами не разделяются: ни память, ни диск, ни шины ввода-вывода. Взаимодействие между компонентами ограничено исключительно обменом сообщениями по сети. Такая изоляция позволяет каждому узлу масштабироваться независимо и устраняет узкие места, характерные для архитектур с общими ресурсами.

Эта модель предполагает, что любая задача может быть декомпозирована на независимые подзадачи, каждая из которых исполняется на отдельном узле без необходимости синхронизации на уровне аппаратуры. Благодаря этому система легко масштабируется горизонтально: добавление нового узла напрямую увеличивает суммарную вычислительную мощность и объём доступного хранилища. Shared Nothing Architecture стала доминирующей парадигмой в проектировании современных высоконагруженных приложений, особенно в облачной среде.

Историческое происхождение

Идея Shared Nothing Architecture была сформулирована в середине 1980-х годов исследователями Дэвидом ДеВиттом и Майклом Стоунабрейкером. Их работы продемонстрировали, что системы, в которых узлы не делят ресурсы, способны достичь значительно более высокой масштабируемости по сравнению с традиционными монолитными базами данных. В то время большинство СУБД строилось на принципах Shared Memory или Shared Disk, где несколько процессоров обращались к единому пулу памяти или дисков. Такие решения упирались в физические ограничения пропускной способности шин и конкуренции за ресурсы.

Shared Nothing Architecture предложила радикально иной взгляд: отказаться от общих ресурсов в пользу полной независимости узлов. Этот подход потребовал пересмотра многих фундаментальных концепций — от управления транзакциями до организации хранения данных. Однако именно он заложил основу для последующего развития распределённых систем, таких как Google Bigtable, Amazon Dynamo, Apache Hadoop и множество современных облачных баз данных.

Шардирование и распределение данных

Центральный механизм Shared Nothing Architecture — шардирование. Данные разделяются на непересекающиеся фрагменты, называемые шардами, каждый из которых целиком принадлежит одному узлу. Шард может содержать часть таблицы, целую таблицу или набор связанных сущностей. Ключевое требование — обеспечить, чтобы запросы к данным затрагивали минимальное число узлов. Это достигается за счёт выбора правильной стратегии распределения.

Наиболее распространённые подходы включают хэш-шардирование, диапазонное шардирование и географическое распределение. Хэш-функция от ключа записи определяет, на каком узле она будет храниться. Диапазонное шардирование группирует записи по значениям ключа — например, все пользователи с ID от 1 до 1000000 попадают в один шард. Географическое распределение учитывает локальность запросов: данные пользователей из Европы хранятся в европейских дата-центрах, а из Азии — в азиатских. Хорошо спроектированная схема шардирования обеспечивает равномерную нагрузку и минимизирует сетевой трафик.

Однако при неудачном выборе ключа шардирования возникает проблема «горячих точек» — некоторые узлы получают непропорционально высокую нагрузку, в то время как другие простаивают. Это снижает общую эффективность системы и усложняет масштабирование. Поэтому проектирование схемы распределения данных является одной из самых ответственных задач при построении Shared Nothing-системы.

Отказоустойчивость и репликация

Поскольку каждый шард физически расположен на одном узле, его потеря приводит к недоступности части данных. Чтобы этого избежать, Shared Nothing Architecture использует репликацию. Каждый шард имеет одну или несколько копий на других узлах. Реплики могут быть синхронными — изменения фиксируются на всех репликах одновременно — или асинхронными — с задержкой, но с меньшим влиянием на производительность.

При отказе основного узла одна из реплик автоматически становится новой основной. Этот процесс, называемый failover, должен быть максимально быстрым и прозрачным для приложения. Для координации реплик и выбора лидера применяются алгоритмы консенсуса, такие как Raft или Paxos. Они гарантируют, что в любой момент времени только один узел считается авторитетным источником данных, что предотвращает расхождение состояний.

Репликация также используется для распределения читаемой нагрузки. Запросы на чтение могут направляться на любую реплику, что снижает нагрузку на основной узел и ускоряет обработку. Однако это требует аккуратного управления согласованностью: при асинхронной репликации клиент может получить устаревшие данные. Выбор уровня согласованности — важный компромисс между производительностью и точностью.

Распределённые транзакции

Одна из сложнейших задач в Shared Nothing Architecture — обеспечение атомарности транзакций, затрагивающих несколько шардов. Поскольку данные физически разделены, изменение должно быть согласовано между всеми участвующими узлами. Для этого применяются протоколы координации, наиболее известный из которых — двухфазный коммит (Two-Phase Commit, 2PC).

В первой фазе координатор отправляет всем участникам запрос на подготовку к коммиту. Каждый участник резервирует ресурсы и сообщает, готов ли он завершить транзакцию. Во второй фазе, если все участники подтвердили готовность, координатор отправляет команду на фиксацию. Если хотя бы один участник отказался, транзакция откатывается. Протокол гарантирует атомарность, но снижает доступность: при потере связи с координатором участники могут надолго блокироваться.

Современные системы всё чаще отказываются от строгих распределённых транзакций в пользу модели eventual consistency или используют альтернативные подходы, такие как Saga-паттерн. В нём транзакция разбивается на последовательность локальных шагов, каждый из которых сопровождается компенсирующим действием на случай отката. Это повышает гибкость и устойчивость, но требует от разработчика явного управления семантикой отката.

Совместимость с микросервисами и облачной инфраструктурой

Shared Nothing Architecture естественным образом сочетается с микросервисной архитектурой. Каждый микросервис владеет своей собственной базой данных и не имеет прямого доступа к данным других сервисов. Взаимодействие происходит через API или очереди сообщений. Такой подход усиливает принципы слабой связанности, автономности и независимого развёртывания.

Облачная инфраструктура идеально подходит для развёртывания Shared Nothing-систем. Облачные провайдеры предоставляют эластичные вычислительные ресурсы, которые можно динамически добавлять или удалять в зависимости от нагрузки. Сервисы балансировки, автоматического масштабирования и управления жизненным циклом контейнеров упрощают эксплуатацию. Кроме того, изоляция узлов повышает отказоустойчивость: сбой в одном экземпляре не влияет на работу остальных.

Практические последствия для разработки

Работа с Shared Nothing Architecture требует особого подхода к проектированию прикладной логики. Разработчик должен учитывать, что данные физически разделены, и избегать запросов, требующих соединения записей из разных шардов. Часто применяются денормализация, материализованные представления и предварительная агрегация, чтобы минимизировать потребность в сложных распределённых операциях.

Это приводит к увеличению объёма хранимых данных, но значительно улучшает производительность и упрощает масштабирование. Также возрастает роль метаданных: система должна знать, где находится каждый шард, каков его статус, какие реплики доступны. Для этого используются каталоги шардов, распределённые реестры и специализированные сервисы оркестрации.